#include "chatserver.hpp"
#include <functional>
#include "json.hpp"
#include "chatservice.hpp"

using namespace std::placeholders;
using nlohmann::json;

class Utils_MsgType;

ChatServer::ChatServer(EventLoop* loop,
                const InetAddress& listenAddr,
                const string& name):
                _server(loop,listenAddr,name),
                _loop(loop)
{
    //注册链接回调函数
    _server.setConnectionCallback(std::bind(&ChatServer::onClientConnection,this,_1));

    //注册读写事件回调函数
    _server.setMessageCallback(std::bind(&ChatServer::onMessage,this,_1,_2,_3));

    //设置线程数量
    //大于等于两个时候muduo会自动将其中一个作为I/O线程，另外的作为工作线程
    _server.setThreadNum(4);
}

//服务器启动服务
void ChatServer::start(){
    _server.start();
}


//客户端连接或断开事件回调函数
void ChatServer::onClientConnection(const TcpConnectionPtr& conn){
    //客户端断开连接
    if(!conn->connected()){
        ChatService::getInstance()->clientCloseException(conn);
        conn->shutdown();
    }
}

/**
 * 客户端读写事件回调函数
 * @param conn: 客户端连接对象
 * @param buffer: 缓冲区
 * @param time: 接收到数据时的时间
 */
void ChatServer::onMessage(const TcpConnectionPtr& conn,Buffer* buffer,Timestamp time){
    //将buffer内容转为string类型
    string buf=buffer->retrieveAllAsString();

    //解析，反序列化
    json js=json::parse(buf);

    //下面代码为了达到一个目的：完全解耦网络模块代码和业务模块代码
    //通过js["msgid"] 获取==>业务handler==>conn js time

    /**
     * 获取事件对应的处理器：
     * 1.先从json获取事件类型msgid
     * 2.将msgid通过工具类转换成EnMsgType枚举类类型
     * 3.获得对应处理器
     */
    EnMsgType type = EnMsgType(js["msgid"].get<int>());
    MsgHandler handler = ChatService::getInstance()->getHandler(type);
    
    //回调消息绑定好的事件处理器，来执行相应的业务
    handler(conn,js,time);
    
}
